package Java工具收集;

import java.security.InvalidParameterException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.commons.lang3.StringUtils;


public class DateUtils {
	public static final String DATE_CHINESE_SHOW_FORMAT = "yyyy年MM月dd日";
	public static final String DATE_HOURS_SHOW_FORMAT = "yyyy-MM-dd HH:mm";
	public static final String DATE_SECOND_SHOW_FORMAT = "yyyy-MM-dd HH:mm:ss";
	public static final String DATE_SHOW_FORMAT = "yyyy-MM-dd";
	public static final Date MIN_DATE = date(1000, 1, 1);
	public static final Date MAX_DATE = date(8888, 1, 1);

	public static String format(Date date, String pattern) {
		if (date != null) {
			SimpleDateFormat df = new SimpleDateFormat(pattern);
			return df.format(date);
		}
		return null;
	}

	public static Date date(int year, int month, int date) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(year, month - 1, date, 0, 0, 0);
		calendar.set(14, 0);
		return calendar.getTime();
	}

	public static int getYearDiff(Date date1, Date date2) {
		if (date1 != null && date2 != null) {
			if (date1.after(date2)) {
				throw new InvalidParameterException("date1 cannot be after date2!");
			} else {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(date1);
				int year1 = calendar.get(1);
				int month1 = calendar.get(2);
				int day1 = calendar.get(5);
				calendar.setTime(date2);
				int year2 = calendar.get(1);
				int month2 = calendar.get(2);
				int day2 = calendar.get(5);
				int result = year2 - year1;
				if (month2 < month1) {
					--result;
				} else if (month2 == month1 && day2 < day1) {
					--result;
				}

				return result;
			}
		} else {
			throw new InvalidParameterException("date1 and date2 cannot be null!");
		}
	}

	public static int getMonthDiff(Date date1, Date date2) {
		if (date1 != null && date2 != null) {
			if (date1.after(date2)) {
				throw new InvalidParameterException("date1 cannot be after date2!");
			} else {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(date1);
				int year1 = calendar.get(1);
				int month1 = calendar.get(2);
				int day1 = calendar.get(5);
				calendar.setTime(date2);
				int year2 = calendar.get(1);
				int month2 = calendar.get(2);
				int day2 = calendar.get(5);
				int months1;
				if (day2 >= day1) {
					months1 = month2 - month1;
				} else {
					months1 = month2 - month1 - 1;
				}

				return (year2 - year1) * 12 + months1;
			}
		} else {
			throw new InvalidParameterException("date1 and date2 cannot be null!");
		}
	}

	public static int getDayDiff(Date date1, Date date2) {
		if (date1 != null && date2 != null) {
			Date startDate = org.apache.commons.lang3.time.DateUtils.truncate(date1, 5);
			Date endDate = org.apache.commons.lang3.time.DateUtils.truncate(date2, 5);
			if (startDate.after(endDate)) {
				throw new InvalidParameterException("date1 cannot be after date2!");
			} else {
				long millSecondsInOneDay = 86400000L;
				return (int) ((endDate.getTime() - startDate.getTime()) / millSecondsInOneDay);
			}
		} else {
			throw new InvalidParameterException("date1 and date2 cannot be null!");
		}
	}

	public static int getMinuteDiffByTime(Date time1, Date time2) {
		long startMil = 0L;
		long endMil = 0L;
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(time1);
		calendar.set(1900, 1, 1);
		startMil = calendar.getTimeInMillis();
		calendar.setTime(time2);
		calendar.set(1900, 1, 1);
		endMil = calendar.getTimeInMillis();
		return (int) ((endMil - startMil) / 1000L / 60L);
	}

	public static Date getPrevDay(Date date) {
		return org.apache.commons.lang3.time.DateUtils.addDays(date, -1);
	}

	public static Date getPrevWeekDay(Date date) {
		return org.apache.commons.lang3.time.DateUtils.addDays(date, -6);
	}

	public static Date getPrevNDay(Date date, int n) {
		return org.apache.commons.lang3.time.DateUtils.addDays(date, -n);
	}

	public static Date getPrevNMonth(Date date, int mount) {
		return org.apache.commons.lang3.time.DateUtils.addMonths(date, mount);
	}

	public static Date getNextDay(Date date) {
		return org.apache.commons.lang3.time.DateUtils.addDays(date, 1);
	}

	public static boolean isDateAfter(Date date1, Date date2) {
		Date theDate1 = org.apache.commons.lang3.time.DateUtils.truncate(date1, 5);
		Date theDate2 = org.apache.commons.lang3.time.DateUtils.truncate(date2, 5);
		return theDate1.after(theDate2);
	}

	public static boolean isDateBefore(Date date1, Date date2) {
		return isDateAfter(date2, date1);
	}

	public static boolean isTimeAfter(Date time1, Date time2) {
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(time1);
		calendar1.set(1900, 1, 1);
		Calendar calendar2 = Calendar.getInstance();
		calendar2.setTime(time2);
		calendar2.set(1900, 1, 1);
		return calendar1.after(calendar2);
	}

	public static boolean isTimeBefore(Date time1, Date time2) {
		return isTimeAfter(time2, time1);
	}

	public static boolean isSameDay(Date date1, Date date2) {
		return org.apache.commons.lang3.time.DateUtils.isSameDay(date1, date2);
	}

	public static boolean isSameDay(Calendar date1, Calendar date2) {
		return org.apache.commons.lang3.time.DateUtils.isSameDay(date1, date2);
	}

	public static Date parseDate(String dateString) {
		if (dateString == null) {
			return null;
		} else {
			try {
				return org.apache.commons.lang3.time.DateUtils.parseDate(dateString,
						new String[]{"yyyy-MM-dd", "yyyy-M-d", "yyyy-MM-d", "yyyy-M-dd","yyyy-MM-dd HH:mm:ss", "yyyy年MM月dd日", "yyyy年MM月"});
			} catch (ParseException arg1) {
				return null;
			}
		}
	}

	public static Date parseTime(String timeString) {
		try {
			return org.apache.commons.lang3.time.DateUtils.parseDate(timeString,
					new String[]{"hh:mm:ss", "h:m:s", "hh:mm", "h:m"});
		} catch (ParseException arg1) {
			return null;
		}
	}

	public static Date parseDateTime(String timeString) {
		try {
			return org.apache.commons.lang3.time.DateUtils.parseDate(timeString,
					new String[]{"yyyy-MM-dd HH:mm:ss.S", "yyyy-MM-dd HH:mm:ss", "yyyy-M-d H:m:s", "yyyy-MM-dd H:m:s",
							"yyyy-M-d HH:mm:ss", "F MMM dd HH:mm:ss z yyyy"});
		} catch (ParseException arg1) {
			return null;
		}
	}

	public static int getWeekDaysBetween(Date fromDate, Date toDate, int dayOfWeek) {
		int result = 0;
		Date firstDate = getFirstWeekdayBetween(fromDate, toDate, dayOfWeek);
		if (firstDate == null) {
			return 0;
		} else {
			Calendar aDay = Calendar.getInstance();
			aDay.setTime(firstDate);

			while (aDay.getTime().before(toDate)) {
				++result;
				aDay.add(5, 7);
			}

			return result;
		}
	}

	public static Date getFirstWeekdayBetween(Date fromDate, Date toDate, int dayOfWeek) {
		Calendar aDay = Calendar.getInstance();
		aDay.setTime(fromDate);

		while (aDay.getTime().before(toDate)) {
			if (aDay.get(7) == dayOfWeek) {
				return aDay.getTime();
			}

			aDay.add(5, 1);
		}

		return null;
	}

	public static int getDaysInYear(int year) {
		Calendar aDay = Calendar.getInstance();
		aDay.set(year, 1, 1);
		Date from = aDay.getTime();
		aDay.set(year + 1, 1, 1);
		Date to = aDay.getTime();
		return getDayDiff(from, to);
	}

	public static int getDaysInMonth(int year, int month) {
		Calendar aDay = Calendar.getInstance();
		aDay.set(year, month, 1);
		Date from = aDay.getTime();
		if (month == 11) {
			aDay.set(year + 1, 0, 1);
		} else {
			aDay.set(year, month + 1, 1);
		}

		Date to = aDay.getTime();
		return getDayDiff(from, to);
	}

	public static int getYear(Date date) {
		return getFieldValue(date, 1);
	}

	public static int getMonth(Date date) {
		return getFieldValue(date, 2) + 1;
	}

	public static int getDayOfYear(Date date) {
		return getFieldValue(date, 6);
	}

	public static int getDayOfMonth(Date date) {
		return getFieldValue(date, 5);
	}

	public static int getDayOfWeek(Date date) {
		return getFieldValue(date, 7);
	}

	private static int getFieldValue(Date date, int field) {
		if (date == null) {
			throw new InvalidParameterException("date cannot be null!");
		} else {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return calendar.get(field);
		}
	}

	public static final Date dateAfter(Date origDate, int amount, int timeUnit) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(origDate);
		calendar.add(timeUnit, amount);
		return calendar.getTime();
	}

	public static final Date dateBefore(Date origDate, int amount, int timeUnit) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(origDate);
		calendar.add(timeUnit, -amount);
		return calendar.getTime();
	}

	public static final Date nowAfter(int amount, int timeUnit) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(timeUnit, amount);
		return calendar.getTime();
	}

	public static Date parseDate(String value, String pattern) throws ParseException {
		return !StringUtils.isBlank(value) && !StringUtils.isBlank(pattern)
				? (new SimpleDateFormat(pattern)).parse(value)
				: null;
	}

	public static String formatString(Date date, String pattern) {
		return date != null && !StringUtils.isBlank(pattern) ? (new SimpleDateFormat(pattern)).format(date) : null;
	}

	public static String formatString(Date date) {
		return date == null ? null : (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(date);
	}

	public static int getDayOfHour(Date date) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		return calendar.get(11);
	}

	public static int getMinute(Date date) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		return calendar.get(12);
	}

	public static Date getArriveTime(Date date, Integer min) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(12, min.intValue());
		return calendar.getTime();
	}

	public static Date getDate(Integer minnute) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(new Date());
		calendar.add(12, minnute.intValue());
		return calendar.getTime();
	}

	public static Timestamp getNextDayTimestamp(Integer day) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(new Date());
		calendar.add(6, day.intValue());
		return new Timestamp(calendar.getTime().getTime());
	}

	public static boolean isAfter(Date date1, Date date2) {
		GregorianCalendar calendar1 = new GregorianCalendar();
		calendar1.setTime(date1);
		GregorianCalendar calendar2 = new GregorianCalendar();
		calendar2.setTime(date2);
		return calendar1.after(calendar2);
	}

	public static Timestamp getTimestamp() {
		Date date = new Date();
		return new Timestamp(date.getTime());
	}

	public static String getTimeNow() {
		Date date = new Date();
		return formatString(date);
	}

	public static Date getSystemDate() {
		return new Date(System.currentTimeMillis() / 86400000L * 86400000L - 28800000L);
	}

	public static Date getDateStart(Date date) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.set(10, 0);
		calendar.set(12, 0);
		calendar.set(13, 0);
		return calendar.getTime();
	}

	public static Date getFirstDateOfMonth(Date date) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.set(5, 1);
		return calendar.getTime();
	}

	public static Date getLastDateOfMonth(Date date) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.set(5, 0);
		calendar.add(2, 1);
		return calendar.getTime();
	}

	public static Date getDateEnd(Date date) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.set(10, 24);
		calendar.set(12, 0);
		calendar.set(13, 0);
		return calendar.getTime();
	}

	public static String getNextHourTime(Date date, int nextHours) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(10, nextHours);
		return formatString(calendar.getTime());
	}

	public static String getNextYearTime(Date date, int nextYears) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(1, nextYears);
		return formatString(calendar.getTime());
	}

	public static String getTimeBucket() {
		Calendar calendar = Calendar.getInstance();
		int hour = calendar.get(11);
		return hour >= 7 && hour < 11
				? "上午"
				: (hour >= 11 && hour < 13
						? "中午"
						: (hour >= 13 && hour < 18 ? "下午" : (hour >= 18 && hour < 23 ? "晚上" : "午夜")));
	}

	public static Date getZeroPointOfDay(Date date) {
		if (date == null) {
			return null;
		} else {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.set(11, 0);
			calendar.set(12, 0);
			calendar.set(13, 0);
			calendar.set(14, 0);
			return calendar.getTime();
		}
	}

	public static Date getLastPointOfDay(Date date) {
		if (date == null) {
			return null;
		} else {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.set(11, 23);
			calendar.set(12, 59);
			calendar.set(13, 59);
			calendar.set(14, 999);
			return calendar.getTime();
		}
	}

	public static Date getZeroPointOfMonth(Date date) {
		if (date == null) {
			return null;
		} else {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.set(5, 1);
			calendar.set(11, 0);
			calendar.set(12, 0);
			calendar.set(13, 0);
			calendar.set(14, 0);
			return calendar.getTime();
		}
	}

	public static Date getLastPointOfMonth(Date date) {
		if (date == null) {
			return null;
		} else {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.set(5, calendar.getActualMaximum(5));
			calendar.set(11, 23);
			calendar.set(12, 59);
			calendar.set(13, 59);
			calendar.set(14, 999);
			return calendar.getTime();
		}
	}

	public static Date addDay(Date date, int days) {
		if (date == null) {
			return null;
		} else {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.add(5, days);
			return calendar.getTime();
		}
	}
}